type EventCallback
    protected
    &(vdom::EventPayload) => Sync;

export function EventCallback:
    &(Sync) => EventCallback
    &(e) => { |EventCallback| &(_) => e };

export function EventCallbackAsync:
    &(Async) => EventCallback
    &(e) => { |EventCallback| &(_) => (Noop with e) };

function EventCallbackDataExtract:[T]
    &(String, (&(vdom::EventPayload,String) => T), (&(T) => EventCallback)) => EventCallback
    &(prop,getter,k) => { |EventCallback| &(ev) =>
        let val := { getter (ev,prop) },
        let next := { k val },
        { next(ev) } };

method EventCallback.EventHandler: Sync[vdom::EventHandler]
    &(cb) => { vdom::EventHandler ({Sink::[Sync] (&(e) => e)}, cb) };


export function extract-string:
    &(String, &(String) => EventCallback) => EventCallback
    &(prop,k) => { EventCallbackDataExtract (prop, vdom::get-string, k) };

export function extract-float:
    &(String, &(NormalFloat) => EventCallback) => EventCallback
    &(prop,k) => { EventCallbackDataExtract (prop, vdom::get-float, k) };

export function extract-integer:
    &(String, &(Integer) => EventCallback) => EventCallback
    &(prop,k) => { EventCallbackDataExtract (prop, vdom::get-integer, k) };

export function extract-number:
    &(String, &(Number) => EventCallback) => EventCallback
    &(prop,k) => { EventCallbackDataExtract (prop, vdom::get-number, k) };

export function extract-bool:
    &(String, &(Bool) => EventCallback) => EventCallback
    &(prop,k) => { EventCallbackDataExtract (prop, vdom::get-bool, k) };

export function extract-rect:
    &((), &(Rect) => EventCallback) => EventCallback
    &(_,k) =>
        \ self::extract-integer let x := 'webuiRectLeft',
        \ self::extract-integer let y := 'webuiRectTop',
        \ self::extract-number let w := 'webuiRectWidth',
        \ self::extract-number let h := 'webuiRectHeight',
        { k { |Rect| {x,y,w,h} } };


